/**
 * Copyright 2011, Under-Ground Studio.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.edu.zju.vlis.aus.chart;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.format.DateFormat;
import android.util.DisplayMetrics;
import cn.edu.zju.vlis.aus.R;
import cn.edu.zju.vlis.aus.bean.UsageRecord;
import cn.edu.zju.vlis.aus.db.UsageRecordDAO;
import cn.edu.zju.vlis.aus.util.IconCache;

/**
 * @author ymsong (songyuming1985@gmail.com) 2011-9-25
 */
public class PieChartAdapter implements ChartDataAdapter {
	// size and metrics
	private static final int POP_CONTENT_PADDING = 10;
	private static final int ICON_TEXT_SPACING = 5;
	private static final int TEXT_SPACEING = 2;
	private static final int ICON_WIDTH = 50;
	private static final int ICON_HEIGHT = 50;
	private static final int TEXT_SIZE_BIG = 16;
	private static final int TEXT_SIZE_SMALL = 12;

	private Context context;
	private DisplayMetrics metrics;
	private final int MAX_PIE_COUNT = 12;
	private final String OTHERS_ID = "_other_items_";
	private List<UsageRecord> usageRecordList;
	private List<UsagePieChartDataItem> pieChartDataList;
	private int count;

	private List<ChartDataAdapterListener> listenerList;

	public PieChartAdapter(Context context, UsageRecordDAO dao) {
		this.context = context;
		metrics = new DisplayMetrics();
		((Activity) context).getWindowManager().getDefaultDisplay()
				.getMetrics(metrics);
		usageRecordList = dao.getRankListByTime();
		// create the chart data items
		if (usageRecordList.size() <= MAX_PIE_COUNT) {
			count = usageRecordList.size();
			pieChartDataList = new ArrayList<UsagePieChartDataItem>(count);
			for (int i = 0; i < count; i++) {
				UsageRecord rec = usageRecordList.get(i);
				pieChartDataList.add(new UsagePieChartDataItem(rec));
			}
		} else {
			count = MAX_PIE_COUNT;
			pieChartDataList = new ArrayList<UsagePieChartDataItem>(count);
			for (int i = 0; i < MAX_PIE_COUNT - 1; i++) {
				UsageRecord rec = usageRecordList.get(i);
				pieChartDataList.add(new UsagePieChartDataItem(rec));
			}
			float othersSum = 0;
			StringBuffer otherAppNames = new StringBuffer();
			for (int i = MAX_PIE_COUNT; i < usageRecordList.size(); i++) {
				othersSum += usageRecordList.get(i).getUseTime();
				if (otherAppNames.length() < 15) {
					otherAppNames.append(usageRecordList.get(i).getAppName())
							.append(",");
				}
			}
			if (otherAppNames.length() > 1) {
				otherAppNames.setLength(otherAppNames.length() - 1);
				otherAppNames.append("...");
			}
			UsagePieChartDataItem othersItem = new UsagePieChartDataItem();
			othersItem.setId(OTHERS_ID);
			String others = context.getResources().getString(
					R.string.pie_chart_others);
			othersItem.setLabel(others);
			othersItem.setNumber(othersSum);
			othersItem.setColor(Color.DKGRAY);
			othersItem.setMetaData(otherAppNames.toString());
			pieChartDataList.add(othersItem);
		}
		listenerList = new ArrayList<ChartDataAdapterListener>();
	}

	@Override
	public int getItemCount() {
		return count;
	}

	@Override
	public ChartDataItem getItem(String id) {
		return null;
	}

	@Override
	public ChartDataItem getItem(int index) {
		return pieChartDataList.get(index);
	}

	@Override
	public void addListener(ChartDataAdapterListener listener) {
		listenerList.add(listener);
	}

	@Override
	public void removeListener(ChartDataAdapterListener listener) {
		listenerList.remove(listener);
	}

	public void fireDataChangeEvent() {
		for (ChartDataAdapterListener listener : listenerList) {
			listener.onDataChanged();
		}
	}

	private class UsagePieChartDataItem extends PieChartDataItem {

		/**
		 * Default constructor.
		 */
		public UsagePieChartDataItem() {
		}

		/**
		 * Constructor using a usage record.
		 * 
		 * @param rec
		 *            usage record
		 */
		public UsagePieChartDataItem(UsageRecord rec) {
			setId(rec.getPackageName());
			setLabel(rec.getAppName());
			setNumber(rec.getUseTime());
			setMetaData(rec.getLastUse());
			setColor(rec.getPackageName().hashCode() | 0xff000000);
		}

		@Override
		public void drawDetail(Canvas canvas, RectF clientArea) {
			// get strings
			String appNameStr = getLabel() + " ("
					+ NumberFormat.getPercentInstance().format(percentage)
					+ ")";
			int useTime = (int) getNumber();
			int hours = useTime / 3600;
			useTime = useTime % 3600;
			int minutes = useTime / 60;
			int seconds = useTime % 60;
			String useTimeStr = context.getResources().getString(
					R.string.text_use_time2, hours, minutes, seconds);
			String lastUseStr = null;
			if (getMetaData() instanceof Long) {
				long lastUse = (Long) getMetaData();
				lastUseStr = context.getString(R.string.text_last_use);
				lastUseStr += (String) DateFormat.format(context
						.getString(R.string.date_format_pattern_last_use),
						lastUse);
			} else {
				lastUseStr = getMetaData().toString();
			}
			// do measure text.
			Rect textBounds = new Rect();
			Rect appNameBounds = new Rect();
			Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
			paint.setTextSize(TEXT_SIZE_BIG * metrics.scaledDensity);
			paint.getTextBounds(appNameStr, 0, appNameStr.length(),
					appNameBounds);
			textBounds.right = appNameBounds.right;
			textBounds.bottom = appNameBounds.height();
			Rect useTimeBounds = new Rect();
			paint.setTextSize(TEXT_SIZE_SMALL * metrics.scaledDensity);
			paint.getTextBounds(useTimeStr, 0, useTimeStr.length(),
					useTimeBounds);
			textBounds.bottom += useTimeBounds.height();
			textBounds.right = textBounds.right > useTimeBounds.right ? textBounds.right
					: useTimeBounds.right;
			Rect lastUseBounds = new Rect();
			paint.getTextBounds(lastUseStr, 0, lastUseStr.length(),
					lastUseBounds);
			textBounds.bottom += lastUseBounds.height();
			textBounds.right = textBounds.right > lastUseBounds.right ? textBounds.right
					: lastUseBounds.right;
			// draw things.
			clientArea.inset(POP_CONTENT_PADDING * metrics.scaledDensity,
					POP_CONTENT_PADDING * metrics.scaledDensity);
			float x = clientArea.left;
			Drawable iconDrawable = IconCache.getIcon(getId());
			if (iconDrawable != null) {
				Bitmap icon = ((BitmapDrawable) iconDrawable).getBitmap();
				RectF iconArea = new RectF(clientArea);
				iconArea.top = clientArea.top
						+ (clientArea.height() - ICON_HEIGHT
								* metrics.scaledDensity) / 2;
				iconArea.right = iconArea.left + ICON_WIDTH
						* metrics.scaledDensity;
				iconArea.bottom = iconArea.top + ICON_WIDTH
						* metrics.scaledDensity;
				x = iconArea.right + ICON_TEXT_SPACING * metrics.scaledDensity;
				canvas.drawBitmap(icon, null, iconArea, null);
			}
			float y = clientArea.top
					+ (clientArea.height() - textBounds.height()) / 2;
			paint.setTextSize(TEXT_SIZE_BIG * metrics.scaledDensity);
			canvas.drawText(appNameStr, x, y - appNameBounds.top, paint);
			y += appNameBounds.height() + TEXT_SPACEING * metrics.scaledDensity;
			paint.setTextSize(TEXT_SIZE_SMALL * metrics.scaledDensity);
			canvas.drawText(useTimeStr, x, y - useTimeBounds.top, paint);
			y += useTimeBounds.height() + TEXT_SPACEING * metrics.scaledDensity;
			canvas.drawText(lastUseStr, x, y - lastUseBounds.top, paint);
		}
	}
}
